package ru.ifmo.rybakov.muclumon.msvs;

import java.rmi.RemoteException;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.apache.axis2.AxisFault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.ifmo.rybakov.muclumon.Cluster;
import ru.ifmo.rybakov.muclumon.Database;
import ru.ifmo.rybakov.muclumon.Revision;
import ru.ifmo.rybakov.muclumon.RevisionType;
import ru.ifmo.rybakov.muclumon.msvs.axis2.ArrayOfString;
import ru.ifmo.rybakov.muclumon.msvs.axis2.Axis2ConversionUtils;
import ru.ifmo.rybakov.muclumon.msvs.axis2.ClusterInfo;
import ru.ifmo.rybakov.muclumon.msvs.axis2.Code;
import ru.ifmo.rybakov.muclumon.msvs.axis2.GetClusterInfo;
import ru.ifmo.rybakov.muclumon.msvs.axis2.GetClusterInfoResponse;
import ru.ifmo.rybakov.muclumon.msvs.axis2.GetClusterList;
import ru.ifmo.rybakov.muclumon.msvs.axis2.GetClusterListResponse;
import ru.ifmo.rybakov.muclumon.msvs.axis2.IntegratorServiceStub;

public class MSVSPollingDaemon implements Runnable {

	private static final Logger logger = LoggerFactory.getLogger(MSVSPollingDaemon.class);
	
	public static final String INTEGRATOR_URL = "http://194.85.163.236/clustmon/";
	
	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		
//		while (true) {
//			String url = "";
//			try {
//				IntegratorServiceStub stub = new IntegratorServiceStub(url);
//				
//				
//				for (int i = 0; i < clusterNames.length; i++) {
//					System.out.println(clusterNames[i]);
//				}
//			} catch (AxisFault e) {
//				
//			} catch (RemoteException e) {
//				
//			}
		buildConfigurationSnapshot(INTEGRATOR_URL);
			
//			try {
//				Thread.sleep(1000);
//			} catch (InterruptedException e) {
//				
//			}
//		}
		
	}
	
//	private void buildClusterStateSnapshot(Revision revision, String clusterName, String url) {
//		logger.info("Begin requesting multi-cluster state (URL={})", url);
//		try {
//			IntegratorServiceStub integrator = new IntegratorServiceStub(url);
//			GetClusterStateInfo request = new GetClusterStateInfo();
//			request.setClusterName(clusterName);
//			GetClusterStateInfoResponse response = integrator.getClusterStateInfo(request);
//			if (!Code.OperationSuccess.equals(response.getErrorCode())) {
//				logger.warn("Unexpected operation result code: {}", response.getErrorCode());
//			} else {
//				ClusterState clusterState = Axis2ConversionUtils.convert(revision, response.getGetClusterStateInfoResult(), clusterName);
//				EntityManager em = Database.getEntityManagerFactory().createEntityManager();
//				try {
//					EntityTransaction t = em.getTransaction();
//					try {
//						t.begin();
//						em.persist(clusterState);
//						t.commit();
//					} finally {
//						if (t.isActive()) t.rollback();
//					}
//				} finally {
//					em.close();
//				}
//			}
//		} catch (AxisFault e) {
//			logger.warn("Unexpected Axis2 exception", e);
//		} catch (RemoteException e) {
//			logger.warn("Unexpected remote I/O exception", e);
//		} catch (Throwable e) {
//			logger.warn("Unexpected exception", e);
//		}
//		logger.info("End requesting multi-cluster state");
//	}
	
	private void buildConfigurationSnapshot(String url) {
		logger.info("Begin requesting multi-cluster configuration (URL={})", url);
		try {
			IntegratorServiceStub integrator = new IntegratorServiceStub(url);
			GetClusterList request = new GetClusterList();
			GetClusterListResponse response = integrator.getClusterList(request);
			ArrayOfString clusterArrayOfString = response.getGetClusterListResult();
			if (clusterArrayOfString == null) {
				logger.warn("ArrayOfString element for cluster array is null in getClusterList response");
				return;
			}
			
			String[] clusterNames = clusterArrayOfString.getString();
			if (clusterNames == null) {
				logger.info("Empty cluster list returned from integrator");
				clusterNames = new String[0];
			}
			
			// create revision
			Revision revision = new Revision();
			revision.setType(RevisionType.CLUSTER_CONFIGURATION);
			
			// persist revision
			EntityManager em = Database.getEntityManagerFactory().createEntityManager();
			try {
				EntityTransaction t = em.getTransaction();
				try {
					t.begin();
					em.persist(revision);
					t.commit();
				} finally {
					if (t.isActive()) {
						t.rollback();
					}
				}
			} finally {
				em.close();
			}
			
			// now fetch every cluster information
			for (String name : clusterNames) {
				buildClusterConfiguration(url, revision, name);
			}
		} catch (AxisFault e) {
			logger.warn("Unexpected Axis2 exception", e);
		} catch (RemoteException e) {
			logger.warn("Unexpected remote I/O exception", e);
		} catch (Throwable e) {
			logger.warn("Unexpected exception", e);
		}
		logger.info("End requesting multi-cluster configuration");
	}
	
	private void buildClusterConfiguration(String url, Revision revision, String clusterName) {
		try {
			IntegratorServiceStub integrator = new IntegratorServiceStub(url);
			GetClusterInfo request = new GetClusterInfo();
			GetClusterInfoResponse response = integrator.getClusterInfo(request);
			if (!Code.OperationSuccess.equals(response.getErrorCode())) {
				logger.warn("Integrator reported on operation failure ({})", response.getErrorCode());
			}
			ClusterInfo clusterInfo = response.getGetClusterInfoResult();
			if (clusterInfo == null) {
				logger.warn("Cluster info was not returned by integrator for cluster '{}'", clusterName);
				return;
			}
			
//			Query query = em.createQuery("SELECT c FROM Cluster c WHERE c.name = :name");
//			query.setParameter("name", clusterName);
//			List<Cluster> clusterList = query.getResultList();
//			if (clusterList == null) {
//				// no cluster found
//			}
			
			// now persist cluster information
			Cluster cluster = Axis2ConversionUtils.convert(revision, clusterInfo);
			EntityManager em = Database.getEntityManagerFactory().createEntityManager();
			try {
				EntityTransaction t = em.getTransaction();
				try {
					t.begin();
					em.persist(cluster);
					t.commit();
				} finally {
					if (t.isActive()) t.rollback();
				}
			} finally {
				em.close();
			}
		} catch (AxisFault e) {
			logger.warn("Unexpected Axis2 exception", e);
		} catch (RemoteException e) {
			logger.warn("Unexpected remote I/O exception", e);
		}
	}
}
